using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using System.Xml;
namespace FirstXNAGame
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        #region Deklaration von Variablen
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        ResourceManager m = new ResourceManager();

        #endregion

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            graphics.PreferredBackBufferHeight = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height;
            graphics.PreferredBackBufferWidth = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width;
            Content.RootDirectory = "Content";
            graphics.ToggleFullScreen();
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            // TODO: use this.Content to load your game content here
            m.Load(this);
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (Keyboard.GetState().IsKeyDown(Keys.Escape))
            {
                this.Exit();
            }
            // TODO: Add your update logic here

            
            m.Update(gameTime,this);
            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // TODO: Add your drawing code here


            spriteBatch.Begin();
            m.Draw(spriteBatch);
            spriteBatch.End();
            base.Draw(gameTime);
        }
    }
    public class ResourceManager
    {
        public LinkedList<Resource> Elements;
        public ResourceManager()
        {
            Elements = new LinkedList<Resource>();
        }
        public void Update(GameTime gameTime,Game g)
        {
            foreach (Resource r in Elements)
            {
                if (r.active && r.type > 0)
                {
                    r.Update(gameTime,g);
                }
            }

        }
        public void Draw(SpriteBatch sb)
        {
            foreach (Resource r in Elements)
            {
                if (r.active && r.visible && r.type > 0)
                {
                    r.Draw(sb);
                }
            }
        }
        public void Load(Game g, ResourceType t, String s)
        {
            Resource tmp = new Resource();
            tmp.Load(g, t, s);
            tmp.active = true;
            tmp.visible = true;
            tmp.type = t;
            Elements.AddLast(tmp);
        }
        public void Load(Game g)
        {
            XmlReader reader = new XmlTextReader("Resources.xml");
            while (reader.Name != "Name" && !reader.EOF) { reader.Read(); }
            while (!reader.EOF)
            {
                #region Parse XML
                while (reader.Name != "Name" ) { reader.Read(); }
                String name = reader.ReadElementContentAsString();

                while (reader.Name != "Type") { reader.Read(); }
                ResourceType type = (ResourceType)reader.ReadElementContentAsInt();

                while (reader.Name != "Filename") { reader.Read(); }
                String filename = reader.ReadElementContentAsString();

                while (reader.Name != "Active") { reader.Read(); }
                bool active = reader.ReadElementContentAsBoolean();

                while (reader.Name != "Visible") { reader.Read(); }
                bool visible = reader.ReadElementContentAsBoolean();

                while (reader.Name != "movable") { reader.Read(); }
                bool movable = reader.ReadElementContentAsBoolean();

                while (reader.Name != "locked") { reader.Read(); }
                bool locked = reader.ReadElementContentAsBoolean();

                while (reader.Name != "animated") { reader.Read(); }
                bool animated = reader.ReadElementContentAsBoolean();

                while (reader.Name != "spriteWidth") { reader.Read(); }
                int spriteWidth = reader.ReadElementContentAsInt();

                while (reader.Name != "spriteHeigth") { reader.Read(); }
                int spriteHeigth = reader.ReadElementContentAsInt();

                while (reader.Name != "frameCount") { reader.Read(); }
                int frameCount = reader.ReadElementContentAsInt();

                while (reader.Name != "interval") { reader.Read(); }
                int interval = reader.ReadElementContentAsInt();

                while (reader.Name != "start_x") { reader.Read(); }
                int start_x = reader.ReadElementContentAsInt();

                while (reader.Name != "start_y") { reader.Read(); }
                int start_y = reader.ReadElementContentAsInt();
                #endregion

                Resource tmp = new Resource();
                tmp.Name = name;
                tmp.type = type;
                tmp.active = active;
                tmp.visible = visible;
                tmp.spriteWidth = spriteWidth;
                tmp.spriteHeigth = spriteHeigth;
                tmp.frameCount = frameCount;
                tmp.interval = interval;
                tmp.locked = locked;
                tmp.movable = movable;
                tmp.start_x = start_x;
                tmp.start_y = start_y;
                tmp.animated = animated;
                tmp.Load(g, type, filename);
                Elements.AddLast(tmp);

                while (reader.Name != "Name" && !reader.EOF) { reader.Read(); }

            }
        }
    }
    public class Resource
    {
        #region Generic Variables
        public String Name;
        public Rectangle dest;
        public Rectangle source;
        public bool active, visible, animated, collision, movable,locked, allow_out_of_screen;
        public ResourceType type;
        public int move_speed,start_x,start_y;
        #endregion
        #region Variable Sprite (Textude 2D animated)
        public Texture2D spriteSheet;
        public double timer;
        public double interval;

        public int frameCount;
        public int currentFrame;

        public int spriteWidth;
        public int spriteHeigth;
        #endregion
        public Resource()
        {
            active = false;
            visible = false;
            animated = false;
            collision = false;
            movable = false;
            locked = false;
            allow_out_of_screen = false;
            type = 0;
            move_speed = 10;
            start_x=0;
            start_y=0;
        }
        public void Load(Game g,ResourceType t, String filename)
        {
            spriteSheet = Texture2D.FromFile(g.GraphicsDevice,filename);
            dest = new Rectangle(start_x, start_x, spriteWidth, spriteHeigth);
        }
        public void Update(GameTime gameTime,Game g)
        {
            #region animation
            if (animated)
            {
                timer += gameTime.ElapsedGameTime.TotalMilliseconds;

                if (timer > interval)
                {
                    currentFrame++;
                    if (currentFrame > frameCount - 1)
                    {
                        currentFrame = 0;
                    }
                    timer = 0;
                }
            }
            #endregion

            #region Input movable
            if (movable && !locked)
            {
                if (Keyboard.GetState().IsKeyDown(Keys.Left))
                {
                    if (0 < dest.X + move_speed)
                        dest.X -= move_speed;
                }

                if (Keyboard.GetState().IsKeyDown(Keys.Right))
                {
                    if (GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width > dest.X + move_speed + spriteWidth)
                    {
                        dest.X += move_speed;
                    }
                    else if (GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width > dest.X + spriteWidth)
                    {
                        dest.X = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width - spriteWidth;
                    }
                }
                if (Keyboard.GetState().IsKeyDown(Keys.Up))
                {
                    if (0 < dest.Y + move_speed)
                        dest.Y -= move_speed;
                }
                if (Keyboard.GetState().IsKeyDown(Keys.Down))
                {
                    if (GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height > dest.Y + move_speed + spriteHeigth)
                    {
                        dest.Y += move_speed;
                    }
                    else if (GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height > dest.Y + spriteHeigth)
                    {
                        dest.Y = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height - spriteHeigth;
                    }
                }
            }
            #endregion

            source = new Rectangle(currentFrame * spriteWidth, 0, spriteWidth, spriteHeigth);

        }
        public void Draw(SpriteBatch sb)
        {
            sb.Draw(spriteSheet, dest, source, Color.White);
        }
    }
    public enum ResourceType : byte
    {
        NotSpecified = 0,
        Texture2D = 1,
        Texture3D = 2
    }
}
